home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacWorld 1999 July
/
Macworld (1999-07).dmg
/
Shareware World
/
Comms & Internet
/
HTML and CSS modes
/
HTML and CSS Modes
/
htmlHomePageUtils.tcl
< prev
next >
Wrap
Text File
|
1999-04-24
|
62KB
|
1,697 lines
## -*-Tcl-*-
# ###################################################################
# HTML mode - tools for editing HTML documents
#
# FILE: "htmlHomePageUtils.tcl"
# created: 97-06-26 12.51.42
# last update: 99-04-24 13.17.59
# Author: Johan Linde
# E-mail: <jlinde@telia.com>
# www: <http://www.theophys.kth.se/~jl/Alpha.html>
#
# Version: 2.1.4
#
# Copyright 1996-1999 by Johan Linde
#
# This software may be used freely, and distributed freely, as long as the
# receiver is not obligated in any way by receiving it.
#
# If you make improvements to this file, please share them!
#
# ###################################################################
##
#===============================================================================
# Checking links
#===============================================================================
# Check that links are valid.
proc htmlCheckWindow {} {htmlCheckLinks Window}
proc htmlCheckHomePage {} {htmlCheckLinks Home}
proc htmlCheckFolder {} {htmlCheckLinks Folder}
proc htmlCheckFile {} {htmlCheckLinks File}
proc htmlIsThereAHomePage {} {
global HTMLmodeVars
if {![llength $HTMLmodeVars(homePages)]} {
alertnote "You must set a home page folder."
htmlHomePages
}
return [llength $HTMLmodeVars(homePages)]
}
proc htmlWhichHomePage {msg} {
global HTMLmodeVars
foreach hp $HTMLmodeVars(homePages) {
lappend hplist "[lindex $hp 1][lindex $hp 2]"
}
if {[catch {listpick -p "Select home page to $msg." $hplist} hp] || ![string length $hp]} {error ""}
set home [lindex $HTMLmodeVars(homePages) [lsearch -exact $hplist $hp]]
if {![file exists [lindex $home 0]] || ![file isdirectory [lindex $home 0]]} {
alertnote "Can't find the folder for [lindex $home 1][lindex $home 2]"
error ""
}
return $home
}
# Checks if a folder contains a home page folder or an include folder as a subfolder.
proc htmlContainHpFolder {folder} {
global HTMLmodeVars
foreach p $HTMLmodeVars(homePages) {
foreach i {0 4} {
if {[llength $p] == $i} {continue}
if {[string match "$folder:*" "[lindex $p $i]:"] && "[lindex $p $i]:" != "$folder:"} {
return 1
}
}
}
return 0
}
proc htmlCheckLinks {where {checking 1}} {
global HTMLmodeVars
# Save all open window?
if {$where != "Window" &&
[htmlAllSaved "-c {Save all open windows before checking links?}"] == "cancel"} { return}
set filebase 0
if {$where == "File"} {
if {[catch {getfile "Select file to scan."} files]} {return}
# Is this a text file?
if {![htmlIsTextFile $files alertnote]} {return}
set base [htmlBASEfromPath $files]
if {$HTMLmodeVars(useBigBrother)} {htmlBigBrother "$files"; return}
set path [lindex $base 1]
set homepage [lindex $base 3]
set isinfld [lindex $base [expr 3 + [lindex $base 4] / 2]]
set base [lindex $base 0]
if {$base == "file:///"} {set filebase [string length "[file dirname $files]:"]}
set filelist [htmlOpenAfile]
puts [lindex $filelist 0] $files
close [lindex $filelist 0]
set files [lindex $filelist 1]
} elseif {$where == "Window"} {
set files [stripNameCount [lindex [winNames -f] 0]]
if {![file exists $files]} {
if {[lindex [dialog -w 200 -h 70 -t "You must save the window." 10 10 390 30 \
-b Save 20 40 85 60 \
-b Cancel 110 40 175 60] 1]} {
error ""
}
if {![catch {saveAs "Untitled.html"}]} {
set files [stripNameCount [lindex [winNames -f] 0]]
} else {
error ""
}
} else {
if {[winDirty] && [askyesno "Save window?"] == "yes"} {save}
}
set base [htmlBASEfromPath $files]
if {$checking != 2 && $HTMLmodeVars(useBigBrother)} {htmlBigBrother "$files"; return}
set path [lindex $base 1]
set homepage [lindex $base 3]
set isinfld [lindex $base [expr 3 + [lindex $base 4] / 2]]
set base [lindex $base 0]
if {$base == "file:///"} {set filebase [string length "[file dirname $files]:"]}
set filelist [htmlOpenAfile]
puts [lindex $filelist 0] $files
close [lindex $filelist 0]
set files [lindex $filelist 1]
} elseif {$where == "Folder"} {
if {[catch {htmlGetDir "Folder to scan."} folder]} {return}
set base [htmlBASEfromPath $folder]
set subFolders [expr ![string compare yes [askyesno "Check files in subfolders?"]]]
if {$subFolders && ![set subFolders [expr ![htmlContainHpFolder $folder]]] &&
[lindex [dialog -w 410 -h 135 -t "The folder '[file tail $folder]' contains a\
home page folder or an include folder, but is itself not inside one. You can't\
simultaneously check links both inside and outside home page or include folders.\
Sorry!\rBut\
you can still check this folder and skip the subfolders." 10 10 400 90\
-b Check 20 105 85 125 -b Cancel 110 105 175 125] 1]} {return}
if {$HTMLmodeVars(useBigBrother)} {htmlBigBrother "$folder:" $subFolders; return}
set path [lindex $base 1]
set homepage [lindex $base 3]
set isinfld [lindex $base [expr 3 + [lindex $base 4] / 2]]
set base [lindex $base 0]
if {$base == "file:///"} {set filebase [string length "$folder:"]}
if {$subFolders} {
set files [htmlAllHTMLfiles $folder 1]
} else {
set files [htmlGetHTMLfiles $folder 1]
}
} else {
# Check that a home page is defined.
if {![htmlIsThereAHomePage]} {return}
if {[catch {htmlWhichHomePage "check links in"} hp]} {return}
set homepage [lindex $hp 0]
set isinfld $homepage
if {$HTMLmodeVars(useBigBrother)} {htmlBigBrother "$homepage:" 1; return}
set files [htmlAllHTMLfiles $homepage 1]
set base [lindex $hp 1]
set path [lindex $hp 2]
}
return [htmlScanFiles $files $base $path $homepage $isinfld $checking $filebase]
}
# Select a new file for an invalid link.
proc htmlLinkToNewFile {} {
if {![string match "*Invalid URLs*" [set win [lindex [winNames] 0]]] || [lindex [posToRowCol [getPos]] 0] < 3} {return}
set str [getText [lineStart [getPos]] [expr [nextLineStart [getPos]] - 1]]
gotoMatch
regexp {Line [0-9]+:([^∞]+)} $str dum url
regsub -all {\((BASE|Invalid|anchor|case)[^\)]+\)} $url "" url
set url [string trim $url]
set str ""
regexp {[^#]*} $url str
set anchor [string trim [string range $url [string length $str] end] \"]
regsub -all {[\(\)]} $url {\\\0} url
if {[catch {search -s -f 1 -i 0 -r 1 -m 0 -l [selEnd] $url [getPos]} res]} {
alertnote "Can't find link to change on selected line."
return
}
if {[set newFile [htmlGetFile 0]] == ""} {return}
set newLink [lindex $newFile 0]
set wh [lindex $newFile 1]
if {$wh == "" && $anchor != "" && [htmlCheckAnchor $pathToNewFile $url]} {
append newLink $anchor
}
set f [htmlURLescape2 $newLink]
if {![regsub {([^=]+=)(\"[^\"]+\"|[^ ]+)} $url "\\1\"$f\"" url]} {set url url(\"$f\")}
replaceText [set start [lindex $res 0]] [lindex $res 1] $url
# If it's an IMG tag, replace WIDTH and HEIGHT.
if {$wh != "" && [string toupper [string range $url 0 2]] == "SRC" &&
![catch {search -s -f 0 -i 1 -r 1 -m 0 {<IMG[ \t\r\n]+[^<>]+>} $start} res1] &&
[lindex $res1 1] > [lindex $res 1]} {
if {![catch {search -s -f 1 -i 1 -r 1 -m 0 -l [expr [lindex $res1 1] + 1] {WIDTH=\"?[0-9]*\"?} [lindex $res1 0]} res2]} {
replaceText [lindex $res2 0] [lindex $res2 1] [htmlSetCase WIDTH=\"[lindex $wh 0]\"]
}
if {![catch {search -s -f 1 -i 1 -r 1 -m 0 -l [expr [lindex $res1 1] + 1] {HEIGHT=\"?[0-9]*\"?} [lindex $res1 0]} res2]} {
replaceText [lindex $res2 0] [lindex $res2 1] [htmlSetCase HEIGHT=\"[lindex $wh 1]\"]
}
}
# Remove line with corrected link.
bringToFront $win
setWinInfo read-only 0
deleteText [lineStart [getPos]] [nextLineStart [getPos]]
select [lineStart [getPos]] [nextLineStart [getPos]]
setWinInfo dirty 0
setWinInfo read-only 1
}
bind '\r' <o> htmlLinkToNewFile Brws
bind enter <o> htmlLinkToNewFile Brws
proc htmlBbthReadSettings {} {
set allSettings [AEBuild -r 'Bbth' core getd ---- "obj{want:type('reco'),from:null(),form:'prop',seld:type('allS')}"]
set allSettings [string range $allSettings 17 [expr [string length $allSettings] - 2]]
return $allSettings
}
proc htmlBbthRestoreSettings {settings} {
AEBuild 'Bbth' core setd "----" "obj{want:type('reco'),from:null(),form:'prop',seld:type('allS')}" "data" $settings
}
proc htmlBigBrother {path {searchSubFolder 0}} {
global HTMLmodeVars
# define url mapping
set urlmap [htmlURLmap]
# launches Big Brother
if {![app::isRunning Bbth] && [catch {app::launchBack Bbth}]} {
alertnote "Could not find or launch Big Brother."
return
}
if {[set vers [htmlGetVersion Bbth]] >= 1.1} {
# Read all settings.
set allSettings [htmlBbthReadSettings]
# Change settings
if {!$HTMLmodeVars(useBBoptions)} {
AEBuild 'Bbth' core setd "----" "obj{want:type('bool'),from:null(),form:'prop',seld:type('Loly')}" "data" "bool(«0$HTMLmodeVars(ignoreRemote)»)"
AEBuild 'Bbth' core setd "----" "obj{want:type('bool'),from:null(),form:'prop',seld:type('Roly')}" "data" "bool(«0$HTMLmodeVars(ignoreLocal)»)"
}
AEBuild 'Bbth' core setd "----" "obj{want:type('bool'),from:null(),form:'prop',seld:type('Sfld')}" "data" "bool(«0$searchSubFolder»)"
AEBuild 'Bbth' core setd "----" "obj{want:type('mapG'),from:null(),form:'prop',seld:type('mapS')}" "data" "\[$urlmap\]"
if {$vers >= 1.2} {
AEBuild 'Bbth' core setd "----" "obj{want:type('bool'),from:null(),form:'prop',seld:type('CasS')}" "data" "bool(«0$HTMLmodeVars(caseSensitive)»)"
}
} else {
alertnote "Cannot change the settings in Big Brother. You need Big Brother 1.1 or later."
}
# Sends a file or folder to be opened.
sendOpenEvent noReply 'Bbth' $path
# Restore settings
if {$vers >= 1.1} {htmlBbthRestoreSettings $allSettings}
if {$HTMLmodeVars(checkInFront)} {switchTo 'Bbth'}
}
# Checking of remote links in a document
proc htmlCheckRemoteLinks {} {
global htmlNumBbthChecking
if {[htmlGetVersion Bbth] < 1.2} {
alertnote "You need Big Brother 1.2 or later to check and fix remote links."
return
}
set urlList [htmlCheckLinks Window 2]
if {![llength $urlList]} {alertnote "No remote links to check."; return}
if {![app::isRunning Bbth] && [catch {app::launchBack Bbth}]} {
alertnote "Could not find or launch Big Brother."
return
}
set htmlBbthChkdWin [stripNameCount [lindex [winNames -f] 0]]
set sep ""
foreach url $urlList {
append theRecord "$sep{Url :“[lindex $url 1]”, Id# :“[concat $url $htmlBbthChkdWin]”}"
set sep ", "
}
# Read all settings.
set allSettings [htmlBbthReadSettings]
# Don't ignore remote links
AEBuild 'Bbth' core setd "----" "obj{want:type('bool'),from:null(),form:'prop',seld:type('Loly')}" "data" "bool(«00»)"
# No url mappings.
AEBuild 'Bbth' core setd "----" "obj{want:type('mapG'),from:null(),form:'prop',seld:type('mapS')}" "data" "\[\]"
AEBuild 'Bbth' "Bbth" "Chck" "----" "\[$theRecord\]"
htmlBbthRestoreSettings $allSettings
incr htmlNumBbthChecking [llength $urlList]
}
# Takes care of events sent from Big Brother.
proc htmlBbthChkdHandler {arg} {
global tileLeft tileTop tileWidth errorHeight htmlNumBbthChecking
regexp {'Id# ':“([^”]+)”} $arg dum id
regexp {CRes:([^,]+)} $arg dum result
set win [lrange $id 2 end]
switch $result {
RSuc {set str "The remote document exists."; set color 3}
LSuc {set str "The local document exists."; set color 3}
SFld {
set color 5
regexp {SCod:([^,]+)} $arg dum code
switch $code {
"204" {set str "The document exists but contains no data."}
"400" {set str "The server (or the proxy) reports a bad request."}
"401" {set str "The document seems to exist but a password is required to access it."}
"403" {set str "The document still exists but the server refuses to deliver it."}
"404" {set str "The remote document doesn't exist."}
"500" {set str "The server reports an internal error while trying to serve our request."}
"501" {set str "The server doesn't seem to support checking the existence of a link."}
"502" {set str "A gateway reported an error."}
"503" {set str "The server is currently unable to deliver this document. This situation might be temporary."}
default {set str "The server answered with an unknown HTTP response code."}
}
}
SMvd {
set color 1
regexp {SCod:([^,]+)} $arg dum code
regexp {nURL:“([^”]+)”} $arg dum newURL
switch $code {
"301" {set str "The document has moved permanently to $newURL."}
"302" {set str "The document has moved temporarily to $newURL."}
default {set str "The document has moved to $newURL."}
}
edit -c -w $win
set l [rowColToPos [lindex $id 0] 0]
if {![catch {search -s -f 1 -i 1 -m 0 -r 0 -l [nextLineStart $l] [lindex $id 1] [lineStart $l]} res]} {
eval replaceText $res $newURL
}
}
sFld {
set color 5
regexp {sRsn:([^,]+)} $arg dum reason
switch $reason {
bnAb {set str "Invalid base URL: it should be an absolute URL."}
nTCP {set str "MacTCP or Open Transport TCP/IP is needed to check remote links."}
locF {set str "Invalid local link."}
Open {set str "Initializing the network services failed."}
Bind {set str "Selecting a local port failed."}
Rslv {set str "Resolving the host name failed."}
Conn {set str "Establishing the connection failed."}
Send {set str "Sending the request failed."}
Recv {set str "Receiving the server's answer failed."}
Disc {set str "Closing the connection failed."}
Pars {set str "The server's response doesn't conform to the HTTP/1.0 protocol."}
Empt {set str "The server closed the connection without answering."}
IncT {set str "The server sent only part of the document."}
SWDr {set str "The server said the document exists, but wasn't able to deliver it."}
NTr/ {set str "This URL should end with a slash because it points to a directory."}
default {set str "Checking the link failed for an unknown reason."}
}
}
Sntx {set str "URL syntax error."; set color 5}
}
if {[lsearch -exact [winNames -f] "* Remote URLs *"] < 0} {
new -n "* Remote URLs *" -g $tileLeft $tileTop $tileWidth $errorHeight -m Brws
insertText "Link checking results: (<uparrow> and <downarrow> to browse, <return> to go to line\rLinks to moved pages have been changed.\r"
htmlSetWin
}
bringToFront "* Remote URLs *"
setWinInfo read-only 0
goto [maxPos]
insertText "Line [lindex $id 0]: "
insertColorEscape [getPos] $color
insertText "$str"
insertColorEscape [getPos] 0
insertText " [lindex $id 1]\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t∞$win\r"
incr htmlNumBbthChecking -1
if {!$htmlNumBbthChecking} {insertText "Done.\r"}
refresh
setWinInfo dirty 0
setWinInfo read-only 1
}
# Returns a list of all HTML and CSS files in a folder and its subfolders.
proc htmlAllHTMLfiles {folder {CSS 0} {toExclude ""}} {
message "Building file list…"
set filelist [htmlOpenAfile]
set fid [lindex $filelist 0]
set files [lindex $filelist 1]
set folders [list $folder]
while {[llength $folders]} {
set newFolders ""
foreach fl $folders {
htmlGetHTMLfiles $fl $CSS $fid $toExclude
# Get folders in this folder.
if {![catch {glob "$fl:*:"} filelist]} {
foreach fil $filelist {
lappend newFolders [string trimright $fil :]
}
}
}
set folders $newFolders
}
close $fid
return $files
}
# Finds all HTML files in a folder
proc htmlGetHTMLfiles {folder {CSS 0} {fid ""} {toExclude ""}} {
global filepats
set pats $filepats(HTML)
if {$CSS && [info exists filepats(CSS)]} {append pats " " $filepats(CSS)}
set files ""
set cl 0
if {$fid == ""} {
set filelist [htmlOpenAfile]
set fid [lindex $filelist 0]
set files [lindex $filelist 1]
set cl 1
}
if {![catch {glob -t TEXT $folder:*} filelist]} {
foreach fil $filelist {
foreach suffix $pats {
if {[string match $suffix $fil] && [lsearch -exact $toExclude $fil] < 0} {
puts $fid $fil
break
}
}
}
}
if {$cl} {close $fid}
return $files
}
# Opens a filelist file. Returns fileid and path.
proc htmlOpenAfile {} {
global PREFS
if {![file exists $PREFS:HTMLtmp]} {mkdir $PREFS:HTMLtmp}
set i 0
while {[file exists $PREFS:HTMLtmp:tempfile$i]} {incr i}
set fid [open $PREFS:HTMLtmp:tempfile$i w+]
return [list $fid "$PREFS:HTMLtmp:tempfile$i"]
}
# checking = 1 or 2: called from htmlCheckLinks
# checking = 1:
# Scan a list of files for HTML links and check if they point to existing files.
# checking = 2:
# Scan a list of files for HTML links and return the remote ones for checking with Big Brother.
# checking = 0: called from htmlMoveFiles
# Build a list of links which point to the files just moved.
proc htmlScanFiles {files baseURL basePath homepage isInFolder checking filebase {movedFiles ""}} {
global htmlURLAttr HTMLmodeVars
global tileLeft tileTop tileWidth errorHeight
global htmlCaseFolders htmlCaseFiles
set htmlCaseFolders ""; set htmlCaseFiles ""
set chCase $HTMLmodeVars(caseSensitive)
set chAnchor $HTMLmodeVars(checkAnchors)
# Build regular expressions with URL attrs.
set exp "<!--|\[ \\t\\n\\r\]+([join $htmlURLAttr |])"
set expBase "<base\[ \\t\\n\\r\]+\[^>\]*>"
set expBase2 "(href=)\"?(\[^ \\t\\n\\r\">\]+)\"?"
set exp1 "${exp}(\"\[^\">\]+\"|\[^ \\t\\n\\r>\]+)"
set exp2 {/\*|[ \t\r\n]+(url)\(\"?([^\"\)]+)\"?\)}
set toCheck ""
if {$checking != 2} {
set result [htmlOpenAfile]
set fidr [lindex $result 0]
}
set checkFail 0
set commStart1 "<!--"
set commEnd1 "-->"
set commStart2 {/*}
set commEnd2 {\*/}
# Open file with filelist
set fid0 [open $files]
while {![eof $fid0]} {
gets $fid0 f
if {$f == "" || [catch {open $f} fid]} {continue}
set base $baseURL
set path $basePath
set hpPath $homepage
if {$isInFolder == ""} {
set epath $f
} else {
set epath [string range $f [expr [string length $isInFolder] + 1] end]
}
regsub -all {:} $epath {/} epath
set baseText ""
message "Looking at [file tail $f]…"
set filecont [read $fid 16384]
set limit [expr [eof $fid] ? 0 : 300]
if {[regexp {\n} $filecont]} {
set newln "\n"
} else {
set newln "\r"
}
# Look for BASE.
if {[regexp -nocase -indices $expBase $filecont thisLine]} {
set preBase [string range $filecont 0 [lindex $thisLine 0]]
set comm 0
while {[regexp -indices {<!--} $preBase bCom]} {
set preBase [string range $preBase [expr [lindex $bCom 1] - 1] end]
set comm 1
if {[regexp -indices -- {-->} $preBase bCom]} {
set preBase [string range $preBase [expr [lindex $bCom 1] - 1] end]
set comm 0
} else {
break
}
}
if {!$comm && [regexp -nocase $expBase2 [string range $filecont [lindex $thisLine 0] [lindex $thisLine 1]] href b url]} {
if {![catch {htmlBASEpieces $url} basestr]} {
set base [lindex $basestr 0]
set path [lindex $basestr 1]
set epath [lindex $basestr 2]
set hpPath ""
set baseText "(BASE used) "
} else {
set baseText "(Invalid BASE) "
}
}
}
for {set i1 1} {$i1 < 3} {incr i1} {
set exprr [set exp$i1]
if {$i1 == 2} {
seek $fid 0
set filecont [read $fid 16384]
set limit [expr [eof $fid] ? 0 : 300]
}
set commStart [set commStart$i1]
set commEnd [set commEnd$i1]
set linenum 1
set comment 0
while {1} {
# Find all links in every line.
while {$comment || ([regexp -nocase -indices $exprr $filecont href b url] &&
[expr [string length $filecont] - [lindex $href 0]] > $limit)} {
# Comment?
if {$comment || [string range $filecont [lindex $href 0] [lindex $href 1]] == $commStart} {
if {$comment} {
set href {0 0}
set subcont $filecont
} else {
set subcont [string range $filecont [expr [lindex $href 1] + 1] end]
}
if {[regexp -indices -- $commEnd $subcont cend] &&
[expr [string length $subcont] - [lindex $cend 0]] > $limit} {
incr linenum [regsub -all $newln [string range $filecont 0 [expr [lindex $href 1] + [lindex $cend 1]]] {} dummy]
set filecont [string range $filecont [expr [lindex $href 1] + [lindex $cend 1]] end]
set comment 0
continue
} else {
set comment 1
break
}
}
incr linenum [regsub -all $newln [string range $filecont 0 [lindex $url 0]] {} dummy]
set linkTo [htmlURLunEscape [string trim [string range $filecont [lindex $url 0] [lindex $url 1]] \"]]
set nogood 0
if {[catch {htmlPathToFile $base $path $epath $hpPath $linkTo} linkToPath]} {
if {$linkToPath == ""} {
set nogood 1
} elseif {$checking == 2 && [string range $linkToPath 0 6] == "http://"} {
# Checking remote links
lappend toCheck [list $linenum $linkToPath]
}
set linkToPath ""
} else {
# Anchors always point to the file itself, unless there's a BASE.
if {[string index $linkTo 0] == "#" && $baseText == ""} {set linkToPath [list $f $f]}
set casePath [lindex $linkToPath 1]
set linkToPath [lindex $linkToPath 0]
}
# If this is BASE HREF, ignore it.
if {[string length $baseText] && [regexp -nocase -indices $expBase $filecont thisLine] \
&& [regexp -nocase $expBase2 [string range $filecont [lindex $thisLine 0] [lindex $thisLine 1]]]\
&& [lindex $thisLine 0] < [lindex $url 0] && [lindex $thisLine 1] > [lindex $url 1]} {
set linkToPath ""
}
if {$checking == 1} {
set anchorCheck 1
set caseOK 1
set fext [file exists $linkToPath]
if {$chAnchor && $linkToPath != "" && [regexp {#} $linkTo] && $fext} {set anchorCheck [htmlCheckAnchor $linkToPath $linkTo]}
if {$chCase && $linkToPath != "" && $fext} {set caseOK [htmlCheckLinkCase $linkToPath $casePath]}
# Does the file exist? Ignore it if it's outside home page folder.
# Then it point to someone else's home page.
if {!$anchorCheck || $nogood || !$caseOK || ( $linkToPath != "" && !$fext)} {
set bText $baseText
if {!$anchorCheck} {append bText "(anchor missing) "}
if {!$caseOK} {append bText "(case doesn't match) "}
if {$homepage == ""} {
set line [string range $f $filebase end]
} else {
set line [string range $f [expr [string length $isInFolder] + 1] end]
}
set l [expr 20 - [string length [file tail $f]]]
set ln [expr 5 - [string length $linenum]]
set href [string trim [string range $filecont [lindex $href 0] [lindex $href 1]]]
append line "[format "%$l\s" ""] Line $linenum:[format "%$ln\s" ""]$bText$href"\
"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t∞$f"
puts $fidr $line
set checkFail 1
}
} elseif {!$checking && [lsearch -exact $movedFiles $linkToPath] >=0 } {
set href [string trim [string range $filecont [lindex $href 0] [lindex $href 1]]]
puts $fidr [list $f $linenum $base $path $epath $linkToPath $href]
}
set filecont [string range $filecont [lindex $url 1] end]
}
if {![eof $fid]} {
incr linenum [regsub -all $newln [string range $filecont 0 [expr [string length $filecont] - 301]] {} dummy]
set filecont "[string range $filecont [expr [string length $filecont] - 300] end][read $fid 16384]"
set limit [expr [eof $fid] ? 0 : 300]
} else {
break
}
}
}
close $fid
}
close $fid0
catch {removeFile $files}
catch {unset htmlCaseFolders htmlCaseFiles filecont}
message ""
if {$checking == 1} {
if {$checkFail} {
seek $fidr 0
new -n "* Invalid URLs *" -g $tileLeft $tileTop $tileWidth $errorHeight -m Brws
insertText "Incorrect links: (<uparrow> and <downarrow> to browse, <return> to go to file,\ropt-<return> to select a new file)\r[read $fidr]"
htmlSetWin
} else {
alertnote "All links are OK."
}
close $fidr
catch {removeFile [lindex $result 1]}
} elseif {!$checking} {
return $result
} else {
return $toCheck
}
}
proc htmlCheckAnchor {anchorFile url} {
regexp {[^#]*#(.*)} $url dum anchor
if {[catch {open $anchorFile r} fid]} {return 1}
set exp "<!--|<(\[Aa\]|\[mM\]\[aA\]\[pP\])\[ \t\r\n\]+\[^>\]*\[nN\]\[aA\]\[mM\]\[eE\]=\"?$anchor\"?(>|\[ \t\r\n\]+\[^>\]*>)"
set filecont [read $fid 16384]
set limit [expr [eof $fid] ? 0 : 300]
set comment 0
while {1} {
while {$comment || ([regexp -indices $exp $filecont anch] &&
[expr [string length $filecont] - [lindex $anch 0]] > $limit)} {
if {$comment || [string range $filecont [lindex $anch 0] [lindex $anch 1]] == "<!--"} {
if {$comment} {
set anch {0 0}
set subcont $filecont
} else {
set subcont [string range $filecont [expr [lindex $anch 1] + 1] end]
}
if {[regexp -indices -- "-->" $subcont cend] &&
[expr [string length $subcont] - [lindex $cend 0]] > $limit} {
set filecont [string range $filecont [expr [lindex $anch 1] + [lindex $cend 1]] end]
set comment 0
continue
} else {
set comment 1
break
}
} else {
close $fid
return 1
}
}
if {![eof $fid]} {
set filecont "[string range $filecont [expr [string length $filecont] - 300] end][read $fid 16384]"
set limit [expr [eof $fid] ? 0 : 300]
} else {
break
}
}
close $fid
return 0
}
# Checks that the case in a link match the case in the path to file.
proc htmlCheckLinkCase {path link} {
global htmlCaseFolders htmlCaseFiles
set path [string trimright $path :]
set link [string trimright $link :]
if {[lsearch -exact $htmlCaseFiles $path] >= 0} {return 1}
set path [split $path :]
set plen [llength $path]
set llen [llength [split $link :]]
set j [expr $plen - $llen ? $plen - $llen - 1 : 0]
for {set i $j} {$i < $plen - 1} {incr i} {
set l [lindex $path [expr $i + 1]]
set psub [join [lrange $path 0 $i] :]
if {[lsearch -exact $htmlCaseFolders $psub] < 0} {
lappend htmlCaseFolders $psub
append htmlCaseFiles " " [glob -nocomplain "$psub:*"]
}
if {[lsearch -exact $htmlCaseFiles "$psub:$l"] < 0} {return 0}
}
return 1
}
#===============================================================================
# Moving files
#===============================================================================
# Moves files from one folder to another and update all links to the moved files
# as well as all links in the moved files.
proc htmlMoveFiles {} {
global HTMLmodeVars
# Check that a home page is defined.
if {![htmlIsThereAHomePage]} {return}
if {[htmlAllSaved "{All windows must be saved before you can moves files. Save?}"] == "no"} {return}
# Get folder to move from.
if {[catch {htmlGetDir "Move from."} fromFolder]} {return}
set base [htmlBASEfromPath $fromFolder]
# Is this folder in a home page folder?
if {[lindex $base 0] == "file:///"} {
alertnote "'[file tail $fromFolder]' is not in a home page folder or an include folder."
return
}
set fromPath [lindex $base 1]
set homepage [lindex $base 3]
set fromBase [lindex $base 0]
set isInInclFldr [lindex $base 4]
set inclFld [lindex $base 5]
# Check that the corresponding include or home page folder exists.
if {$isInInclFldr} {
if {![file isdirectory $homepage]} {
alertnote "Could not find the corresponding home page folder for\
${fromBase}$fromPath. Fix that and try again."
htmlHomePages "${fromBase}$fromPath"
return
}
} elseif {$inclFld != "" && ![file isdirectory $inclFld]} {
alertnote "Could not find the corresponding include folder for\
${fromBase}$fromPath. Fix that and try again."
htmlHomePages "${fromBase}$fromPath"
return
}
# Get files to move.
set files [glob -nocomplain "$fromFolder:*"]
foreach f $files {
if {![file isdirectory $f]} {
lappend filelist [file tail $f]
}
}
if {![info exists filelist]} {
alertnote "Empty folder."
return
}
if {[catch {listpick -p "Select files to move." -l $filelist} movefiles] || \
![string length $movefiles]} {return}
# Get folder to move to.
if {[catch {htmlGetDir "Move to."} toFolder]} {return}
if {$fromFolder == $toFolder} {
alertnote "This is the same folder as you moved from."
return
}
# Is this folder in the same home page folder?
if {!$isInInclFldr && ![string match "${homepage}:*" "$toFolder:"] ||
$isInInclFldr && ![string match "${inclFld}:*" "$toFolder:"]} {
set msg {"home page" "" "" "" "include"}
alertnote "'[file tail $toFolder]' is not in the same [lindex $msg $isInInclFldr] folder."
return
}
# Move the files.
foreach f $movefiles {
if {[file exists "$toFolder:$f"]} {
if {[askyesno "Replace '$f' in folder '[file tail $toFolder]'?"] == "yes"} {
removeFile "$toFolder:$f"
} else {
continue
}
}
set reo 0
foreach w [winNames -f] {
if {[stripNameCount $w] == "$fromFolder:$f"} {
alertnote "'[file tail $w]' must be closed before it can be moved. It will be reopened again."
bringToFront $w
killWindow
set reo 1
}
}
if {[catch {moveFile "$fromFolder:$f" "$toFolder:$f"}] && ![file exists "$toFolder:$f"]} {
alertnote "Could not move $f. An error occurred."
if {$reo} {lappend reOpen "$fromFolder:$f"}
} else {
lappend movedFiles "$fromFolder:$f"
lappend movedFiles2 "$toFolder:$f"
if {$reo} {lappend reOpen "$toFolder:$f"}
}
}
if {[info exists movedFiles] && [lindex [dialog -w 400 -h 70 -t "Files have been moved. Update links?" \
10 10 290 30 -b Update 20 40 85 60 -b Cancel 105 40 170 60] 0]} {
if {$isInInclFldr} {
set x [htmlUpdateAfterMove3 $movedFiles $movedFiles2 $homepage $inclFld]
set num [lindex $x 0]
set changed [lindex $x 1]
} else {
set x [htmlUpdateAfterMove $movedFiles $movedFiles2 $fromBase $fromPath $homepage $homepage]
set num [lindex $x 0]
set changed [lindex $x 1]
incr num [htmlUpdateAfterMove2 $movedFiles $movedFiles2 $fromBase $fromPath $homepage]
}
}
catch {message "$num files has been modified including the ones moved."}
if {[info exists reOpen] && [askyesno "Reopen previously closed windows?"] == "yes"} {
foreach r $reOpen {
edit $r
}
}
if {[llength $changed] && [askyesno "Update affected windows?"] == "yes"} {
foreach r $changed {
bringToFront $r
revert
}
}
}
# Updates links to moved files.
proc htmlUpdateAfterMove {movedFiles movedFiles2 fromBase fromPath homepage isinfld} {
global htmlURLAttr
set allfiles [htmlAllHTMLfiles $isinfld 1 $movedFiles2]
# Build regular expressions with URL attrs.
set exp "([join $htmlURLAttr |])"
set exprr "${exp}(\"\[^\">\]+\"|\[^ \\t\\n\\r>\]+)"
set exprr2 {(url)\((\"?[^\"\)]+\"?)\)}
# Update links to the moved files.
set toModify [htmlScanFiles $allfiles $fromBase $fromPath $homepage $isinfld 0 0 $movedFiles]
set fidr [lindex $toModify 0]
seek $fidr 0
set num 0
set changed ""
set thisfile ""
while {![eof $fidr]} {
gets $fidr modify
if {$modify == ""} {continue}
set fil [lindex $modify 0]
if {$thisfile != $fil} {
if {[string length $thisfile]} {
if {[catch {open $thisfile w} fid]} {
alertnote "Could not update [file tail $thisfile]. An error occurred."
} else {
puts -nonewline $fid [join $filecont "\r"]
close $fid
}
}
message "Modifying [file tail $fil]…"
foreach w [winNames -f] {
if {[stripNameCount $w] == "$fil"} {
lappend changed $w
}
}
set fid [open $fil r]
incr num
set filec [read $fid]
close $fid
if {[regexp {\n} $filec]} {
set newln "\n"
} else {
set newln "\r"
}
set filec [split $filec $newln]
set filecont ""
foreach fc $filec {
lappend filecont [string trimleft $fc "\r"]
}
}
set thisfile $fil
set linenum [expr [lindex $modify 1] - 1]
set line [lindex $filecont $linenum]
set path [lindex $movedFiles2 [lsearch -exact $movedFiles [lindex $modify 5]]]
set lnk [htmlBASEfromPath $path]
if {[lindex $modify 2] == [lindex $lnk 0]} {
set linkTo [htmlRelativePath "[lindex $modify 3][lindex $modify 4]" "[lindex $lnk 1][lindex $lnk 2]"]
} else {
set linkTo [join [lrange $lnk 0 2] ""]
}
set linkTo [htmlURLescape2 $linkTo]
regsub -all {[\(\)]} [lindex $modify 6] {\\\0} tomod
regexp -indices $tomod $line href
if {![regexp -nocase -indices $exprr [string range $line [lindex $href 0] [lindex $href 1]] a b url]} {
regexp -nocase -indices $exprr2 [string range $line [lindex $href 0] [lindex $href 1]] a b url
}
set anchor ""
regexp {[^#]*(#[^\"]*)} $tomod a anchor
set line "[string range $line 0 [expr [lindex $href 0] + [lindex $url 0] - 1]]\"$linkTo$anchor\"[string range $line [expr [lindex $href 0] + [lindex $url 1] + 1] end]"
set filecont [lreplace $filecont $linenum $linenum $line]
}
if {$thisfile != ""} {
if {[catch {open $thisfile w} fid]} {
alertnote "Could not update [file tail $thisfile]. An error occurred."
} else {
puts -nonewline $fid [join $filecont "\r"]
close $fid
}
}
close $fidr
catch {removeFile [lindex $toModify 1]}
return [list $num $changed]
}
# Updates links in moved files.
proc htmlUpdateAfterMove2 {movedFiles movedFiles2 fromBase fromPath homepage} {
global htmlURLAttr
set expBase "<(base\[ \\t\\n\\r\]+)\[^>\]*>"
set expBase2 "(href=)\"?(\[^ \\t\\n\\r\">\]+)\"?"
# Build regular expressions with URL attrs.
set exp "([join $htmlURLAttr |])"
set exprr1 "<!--|\[ \\t\\n\\r\]+$exp\"?(\[^ \\t\\n\\r\">\]+)\"?"
set exprr2 {/\*|[ \t\n\r]+(url)\(\"?([^\"\)]+)\"?\)}
set commStart1 "<!--"
set commEnd1 "-->"
set commStart2 {/*}
set commEnd2 {\*/}
set num 0
foreach f $movedFiles2 {
getFileInfo $f finfo
if {$finfo(type) != "TEXT"} {continue}
message "Modifying [file tail $f]…"
set created $finfo(created)
set fid [open $f r]
set filecont [read $fid 16384]
set limit [expr [eof $fid] ? 0 : 300]
set temp [htmlOpenAfile]
set tempf [lindex $temp 1]
set tempfid [lindex $temp 0]
set oldfile [lindex $movedFiles [lsearch -exact $movedFiles2 $f]]
set base $fromBase
set path $fromPath
set hpPath $homepage
set epath [string range $oldfile [expr [string length $homepage] + 1] end]
regsub -all {:} $epath {/} epath
# Replace newline chars in IBM files.
regsub -all "\n\r" $filecont "\r" filecont
# If BASE is used, only modify links to moved files.
set hasBase 0
if {[regexp -nocase -indices $expBase $filecont this]} {
set preBase [string range $filecont 0 [lindex $this 0]]
set comm 0
while {[regexp -indices {<!--} $preBase bCom]} {
set preBase [string range $preBase [expr [lindex $bCom 1] - 1] end]
set comm 1
if {[regexp -indices -- {-->} $preBase bCom]} {
set preBase [string range $preBase [expr [lindex $bCom 1] - 1] end]
set comm 0
} else {
break
}
}
if {!$comm && [regexp -nocase $expBase2 [string range $filecont [lindex $this 0] [lindex $this 1]] d1 d2 url1]} {
set hasBase 1
}
}
if {$hasBase && ![catch {htmlBASEpieces $url1} basestr]} {
set base [lindex $basestr 0]
set path [lindex $basestr 1]
set epath [lindex $basestr 2]
set hpPath ""
}
incr num
for {set i1 1} {$i1 < 3} {incr i1} {
if {$i1 == 2} {
close $fid
seek $tempfid 0
set fid $tempfid
set filecont [read $fid 16384]
set limit [expr [eof $fid] ? 0 : 300]
set temp [htmlOpenAfile]
set tempfid [lindex $temp 0]
}
set commStart [set commStart$i1]
set commEnd [set commEnd$i1]
set exprr [set exprr$i1]
set comment 0
while {1} {
while {$comment || ([regexp -nocase -indices $exprr $filecont href b url] &&
[expr [string length $filecont] - [lindex $href 0]] > $limit)} {
# Comment?
if {$comment || [string range $filecont [lindex $href 0] [lindex $href 1]] == $commStart} {
if {$comment} {
set href {0 0}
set subcont $filecont
} else {
set subcont [string range $filecont [expr [lindex $href 1] + 1] end]
}
if {[regexp -indices -- $commEnd $subcont cend] &&
[expr [string length $subcont] - [lindex $cend 0]] > $limit} {
puts -nonewline $tempfid [string range $filecont 0 [expr [lindex $href 1] + [lindex $cend 1] - 1]]
set filecont [string range $filecont [expr [lindex $href 1] + [lindex $cend 1]] end]
set comment 0
continue
} else {
set comment 1
break
}
}
set urltxt [string range $filecont [lindex $url 0] [lindex $url 1]]
# No need to update links beginning with a /
if {[string index $urltxt 0] == "/"} {
puts -nonewline $tempfid [string range $filecont 0 [lindex $url 1]]
set filecont [string range $filecont [expr [lindex $url 1] + 1] end]
continue
}
set anchor ""
regexp {[^#]*(#[^\"]*)} $urltxt a anchor
set urltxt [htmlURLunEscape $urltxt]
if {[catch {lindex [htmlPathToFile $base $path $epath $hpPath $urltxt] 0} topath]} {set topath ""}
# Ignore anchors if not moved and BASE.
# Is the link pointing to a previously moved file?
if {[set mvind [lsearch -exact $movedFiles $topath]] >= 0} {
set topath [lindex $movedFiles2 $mvind]
if {!$hasBase && [string index $urltxt 0] == "#"} {set topath ""}
} elseif {[string index $urltxt 0] == "#"} {
set topath ""
}
if {$hasBase && [regexp -nocase -indices $expBase $filecont thisLine] \
&& [regexp -nocase $expBase2 [string range $filecont [lindex $thisLine 0] [lindex $thisLine 1]]]\
&& [lindex $thisLine 0] < [lindex $url 0] && [lindex $thisLine 1] > [lindex $url 1]} {
set topath ""
}
if {[string length $topath]} {
set lnk [htmlBASEfromPath $topath]
if {!$hasBase} {
set lnk1 [htmlBASEfromPath $f]
set path2 [lindex $lnk1 1]
set epath2 [lindex $lnk1 2]
} else {
set path2 $path
set epath2 $epath
}
if {$base == [lindex $lnk 0]} {
set newurl [htmlRelativePath "$path2$epath2" "[lindex $lnk 1][lindex $lnk 2]"]
} else {
set newurl [join [lrange $lnk 0 2] ""]
}
append newurl $anchor
} elseif {!$hasBase && ($urltxt == ".." || [string range $urltxt 0 2] == "../")} {
# Special case with relative links outside home page.
set urlspl [split $urltxt /]
set old [split $oldfile :]
set new [split $f :]
if {[llength $new] > [llength $old]} {
set newurl ""
for {set i 0} {$i < [expr [llength $new] - [llength $old]]} {incr i} {
append newurl "../"
}
append newurl $urltxt
} else {
set ok 1
for {set i 0} {$i < [expr [llength $old] - [llength $new]]} {incr i} {
if {[lindex $urlspl $i] != ".."} {set ok 0}
}
if {$ok} {
set newurl "[join [lrange $urlspl [expr [llength $old] - [llength $new]] end] /]$anchor"
} else {
set newurl $urltxt
}
}
} else {
set newurl $urltxt
}
puts -nonewline $tempfid [string range $filecont 0 [expr [lindex $url 0] - 1]]
puts -nonewline $tempfid [htmlURLescape2 $newurl]
set filecont [string range $filecont [expr [lindex $url 1] + 1] end]
}
if {![eof $fid]} {
puts -nonewline $tempfid [string range $filecont 0 [expr [string length $filecont] - 301]]
set filecont "[string range $filecont [expr [string length $filecont] - 300] end][read $fid 16384]"
set limit [expr [eof $fid] ? 0 : 300]
} else {
break
}
}
puts -nonewline $tempfid $filecont
}
close $fid
close $tempfid
if {[catch {removeFile $f}] && [file exists $f]} {
alertnote "Could not update [file tail $f]. An error occurred."
} else {
catch {copyFile [lindex $temp 1] $f; setFileInfo $f created $created}
}
catch {removeFile [lindex $temp 1]}
catch {removeFile $tempf}
}
return $num
}
# Updates include links to moved files in include folder.
proc htmlUpdateAfterMove3 {movedFiles movedFiles2 homepage inclFldr} {
set num 0
set changed ""
set allFiles [htmlAllHTMLfiles $homepage]
set fid0 [open $allFiles]
while {![eof $fid0]} {
gets $fid0 fil
if {$fil == "" || [catch {open $fil} fid]} {continue}
set filecont [read $fid 16384]
set limit [expr [eof $fid] ? 0 : 300]
message "Looking at [file tail $fil]…"
getFileInfo $fil finfo
set created $finfo(created)
regsub -all "\n\r" $filecont "\r" filecont
set temp [htmlOpenAfile]
set tmpfid [lindex $temp 0]
set ismod 0
while {1} {
while {[regexp -nocase -indices {<!--[ \t\r\n]+#INCLUDE[ \t\r\n]+[^>]+>} $filecont res] &&
[expr [string length $filecont] - [lindex $res 0]] > $limit} {
set link [string range $filecont [lindex $res 0] [lindex $res 1]]
if {[regexp -nocase -indices {FILE=\"([^\"]+)\"} $link dum res1] &&
[set ind [lsearch -exact $movedFiles [htmlResolveInclPath [htmlUnQuote \
[string range $link [lindex $res1 0] [lindex $res1 1]]] $inclFldr:]]] >= 0} {
puts -nonewline $tmpfid [string range $filecont 0 [expr [lindex $res 0] + [lindex $res1 0] - 1]]
puts -nonewline $tmpfid [htmlQuote [htmlConvertInclPath [lindex $movedFiles2 $ind] $inclFldr:]]
puts -nonewline $tmpfid [string range $filecont [expr [lindex $res 0] + [lindex $res1 1] + 1] [lindex $res 1]]
set ismod 1
message "Modifying [file tail $fil]…"
} else {
puts -nonewline $tmpfid [string range $filecont 0 [lindex $res 1]]
}
set filecont [string range $filecont [expr [lindex $res 1] + 1] end]
}
if {![eof $fid]} {
puts -nonewline $tmpfid [string range $filecont 0 [expr [string length $filecont] - 301]]
set filecont "[string range $filecont [expr [string length $filecont] - 300] end][read $fid 16384]"
set limit [expr [eof $fid] ? 0 : 300]
} else {
break
}
}
puts -nonewline $tmpfid $filecont
close $tmpfid
close $fid
if {$ismod} {
if {[catch {removeFile $fil}] && [file exists $fil]} {
alertnote "Could not update [file tail $fil]. An error occurred."
} else {
catch {copyFile [lindex $temp 1] $fil; setFileInfo $fil created $created}
}
incr num
foreach w [winNames -f] {
if {[stripNameCount $w] == "$fil"} {
lappend changed $w
}
}
}
catch {removeFile [lindex $temp 1]}
}
close $fid0
catch {removeFile $allFiles}
return [list $num $changed]
}
#===============================================================================
# Includes
#===============================================================================
proc htmlConvertInclPath {fil path} {
if {$path != "" && [string match "${path}*" $fil]} {
return ":INCLUDE:[string range $fil [string length $path] end]"
}
return $fil
}
proc htmlPasteIncludeTags {} {
global htmlHomePageWinURL
if {![info exists htmlHomePageWinURL]} {message "No file to paste."; return}
htmlInsertIncludeTags $htmlHomePageWinURL
}
# Inserts new include tags at the current position.
proc htmlInsertIncludeTags {{fil ""}} {
global HTMLmodeVars
set sexpr {<!--[ \t\r\n]+#INCLUDE[ \t\r\n]+[^>]+>}
set eexpr {<!--[ \t\r\n]+/#INCLUDE[ \t\r\n]+[^>]+>}
if {![catch {search -s -f 0 -r 1 -i 1 -m 0 $sexpr [getPos]} res] &&
([catch {search -s -f 0 -r 1 -i 1 -m 0 $eexpr [getPos]} res1]
|| [lindex $res 0] > [lindex $res1 0])} {
alertnote "Current position is inside an include container."
return
}
if {![catch {search -s -f 1 -r 1 -i 1 -m 0 $eexpr [getPos]} res] &&
([catch {search -s -f 1 -r 1 -i 1 -m 0 $sexpr [getPos]} res1]
|| [lindex $res 0] < [lindex $res1 0])} {
alertnote "Current position is inside an include container."
return
}
if {$fil == "" && [catch {getfile "Select file to include."} fil]} {return}
if {![htmlIsTextFile $fil alertnote]} {return}
set fil1 [htmlQuote [htmlConvertInclPath $fil \
[htmlWhichInclFolder [stripNameCount [lindex [winNames -f] 0]]]]]
set text "<!-- [htmlSetCase {#INCLUDE FILE=}]\"$fil1\" -->\r\r"
if {$HTMLmodeVars(includeOnlyTags)} {append text "<B>The file [file tail $fil1] will be inserted here when the window is updated.</B>"}
append text "\r\r" "<!-- [htmlSetCase /#INCLUDE] -->"
insertText [htmlOpenCR "" 1] $text "\r\r"
if {!$HTMLmodeVars(includeOnlyTags)} {htmlUpdateWindow $fil1}
}
# Updates the text between all include tags.
proc htmlUpdateWindow {{fil ""}} {htmlUpdateInclude Window $fil}
proc htmlUpdateHomePage {} {htmlUpdateInclude Home}
proc htmlUpdateFolder {} {htmlUpdateInclude Folder}
proc htmlUpdateFile {} {htmlUpdateInclude File}
proc htmlUpdateInclude {where {onlyThis ""}} {
global HTMLmodeVars PREFS htmlUpdateErr htmlUpdateList htmlUpdateBase htmlUpdatePath htmlUpdateHome
global tileLeft tileTop tileWidth errorHeight
# Clean up after previous update
if {[file exists $PREFS:HTMLtmp:incl]} {catch {rm -r $PREFS:HTMLtmp:incl}}
if {[file exists $PREFS:HTMLtmp:xincl]} {catch {rm -r $PREFS:HTMLtmp:xincl}}
set sexpr {<!--[ \t\r\n]+#INCLUDE[ \t\r\n]+[^>]+>}
set eexpr {<!--[ \t\r\n]+/#INCLUDE[ \t\r\n]+[^>]+>}
set expBase "<(base\[ \\t\\n\\r\]+)\[^>\]*>"
set expBase2 "(href=)\"?(\[^ \\t\\n\\r\">\]+)\"?"
set htmlUpdateErr ""
if {$where == "Window"} {
set wname [stripNameCount [lindex [winNames -f] 0]]
set htmlUpdateList $wname
set inclFldr [htmlWhichInclFolder $wname]
set home [htmlWhichHomeFolder $wname]
if {$home != ""} {
set htmlUpdateBase [lindex $home 1]
set htmlUpdatePath [lindex $home 2]
set htmlUpdateHome [list [lindex $home 1] [lindex $home 2]]
} else {
set htmlUpdateHome [list [set htmlUpdateBase "file:///"] ""]
regsub -all : [file dirname $wname] / htmlUpdatePath
}
regsub -all : [string range $wname [expr [string length [lindex $home 0]] + 1] end] / tp
append htmlUpdatePath [string range $tp 0 [string last / $tp]]
set hasBase 0
if {![catch {search -s -f 1 -i 1 -m 0 -r 1 $expBase 0} this]} {
set preBase [lindex $this 0]
set comm 0
set spos 0
while {![catch {search -s -f 1 -i 1 -m 0 -l $preBase {<!--} $spos} bCom]} {
set spos [lindex $bCom 1]
set comm 1
if {![catch {search -s -f 1 -i 1 -m 0 -l $preBase -- {-->} $spos} bCom]} {
set spos [lindex $bCom 1]
set comm 0
} else {
break
}
}
if {!$comm && [regexp -nocase $expBase2 [getText [lindex $this 0] [lindex $this 1]] d1 d2 url1]} {
set hasBase 1
}
}
if {$hasBase && ![catch {htmlBASEpieces $url1} basestr]} {
set htmlUpdateBase [lindex $basestr 0]
set tp [lindex $basestr 2]
set htmlUpdatePath "[lindex $basestr 1][string range $tp 0 [string last / $tp]]"
}
set pos 0
while {![catch {search -s -f 1 -r 1 -i 1 -m 0 $sexpr $pos} res]} {
set lnum [lindex [posToRowCol [lindex $res 0]] 0]
set ln [expr 5 - [string length $lnum]]
if {[catch {search -s -f 1 -r 1 -i 1 -m 0 $eexpr [lindex $res 1]} res1]} {
append htmlUpdateErr "Line $lnum:[format "%$ln\s" ""]Opening include tag without a matching end tag."\
"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t∞$wname\r"
break
}
if {![catch {search -s -f 1 -r 1 -i 1 -m 0 $sexpr [lindex $res 1]} res2]
&& [lindex $res2 0] < [lindex $res1 0]} {
append htmlUpdateErr "Line $lnum:[format "%$ln\s" ""]Nested include tags."\
"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t∞$wname\r"
set pos [lindex $res1 1]
continue
}
if {[catch {htmlReadInclude [eval getText $res] 1 $inclFldr 0 $onlyThis} text]} {
if {$text != "Not this file"} {append htmlUpdateErr "Line $lnum:[format "%$ln\s" ""]$text"\
"\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t∞$wname\r"}
set pos [lindex $res1 1]
} else {
replaceText [lindex $res 1] [lindex $res1 0] "\r\r" $text "\r\r"
set pos [expr [lindex $res 1] + [string length $text] + 4]
}
}
} else {
if {[htmlAllSaved "-c {Save all open windows before updating?}"] == "cancel"} {return}
if {$where == "File"} {
if {[catch {getfile "Select file to update."} files]} {return}
if {![htmlIsTextFile $files alertnote]} {return}
set inclFldr [htmlWhichInclFolder $files]
set home [htmlWhichHomeFolder $files]
set folder [file dirname $files]
set filelist [htmlOpenAfile]
puts [lindex $filelist 0] $files
close [lindex $filelist 0]
set files [lindex $filelist 1]
} elseif {$where == "Folder"} {
if {[catch {htmlGetDir "Update folder:"} folder]} {return}
set inclFldr [htmlWhichInclFolder "${folder}:"]
set home [htmlWhichHomeFolder "${folder}:"]
set subFolders [expr ![string compare yes [askyesno "Update files in subfolders?"]]]
if {$subFolders} {
set files [htmlAllHTMLfiles $folder]
} else {
set files [htmlGetHTMLfiles $folder]
}
} else {
if {![htmlIsThereAHomePage] ||
[catch {htmlWhichHomePage "update"} home]} {return}
set folder [lindex $home 0]
set inclFldr [htmlWhichInclFolder "${folder}:"]
set files [htmlAllHTMLfiles $folder]
}
set fid0 [open $files]
while {![eof $fid0]} {
gets $fid0 f
if {$f == "" || [catch {open $f} fid1]} {continue}
set filecont [read $fid1 16384]
close $fid1
if {$home != ""} {
set htmlUpdateBase [lindex $home 1]
set htmlUpdatePath [lindex $home 2]
set htmlUpdateHome [list [lindex $home 1] [lindex $home 2]]
} else {
set htmlUpdateHome [list [set htmlUpdateBase "file:///"] ""]
regsub -all : [file dirname $f] / htmlUpdatePath
}
regsub -all : [string range $f [expr [string length [lindex $home 0]] + 1] end] / tp
append htmlUpdatePath [string range $tp 0 [string last / $tp]]
set hasBase 0
if {[regexp -nocase -indices $expBase $filecont this]} {
set preBase [string range $filecont 0 [lindex $this 0]]
set comm 0
while {[regexp -indices {<!--} $preBase bCom]} {
set preBase [string range $preBase [expr [lindex $bCom 1] - 1] end]
set comm 1
if {[regexp -indices -- {-->} $preBase bCom]} {
set preBase [string range $preBase [expr [lindex $bCom 1] - 1] end]
set comm 0
} else {
break
}
}
if {!$comm && [regexp -nocase $expBase2 [string range $filecont [lindex $this 0] [lindex $this 1]] d1 d2 url1]} {
set hasBase 1
}
}
if {$hasBase && ![catch {htmlBASEpieces $url1} basestr]} {
set htmlUpdateBase [lindex $basestr 0]
set tp [lindex $basestr 2]
set htmlUpdatePath "[lindex $basestr 1][string range $tp 0 [string last / $tp]]"
}
set htmlUpdateList $f
if {[htmlUpdateOneFile $f $f $folder $inclFldr 0]} {lappend modified $f}
}
close $fid0
catch {removeFile $files}
}
if {$htmlUpdateErr != ""} {
new -n "* Errors *" -g $tileLeft $tileTop $tileWidth $errorHeight -m Brws
set name [lindex [winNames] 0]
insertText "Errors: (<uparrow> and <downarrow> to browse, <return> to go to file)\r\r"
insertText $htmlUpdateErr
htmlSetWin
} else {
message "$where updated successfully."
}
if {[info exists modified]} {
foreach w [winNames -f] {
if {[lsearch -exact $modified [stripNameCount $w]] >= 0} {
if {[askyesno "Update affected windows?"] == "yes"} {
foreach ww [winNames -f] {
if {[lsearch -exact $modified [stripNameCount $ww]] >= 0} {
bringToFront $ww
revert
}
}
}
if {$htmlUpdateErr != ""} {bringToFront $name}
break
}
}
}
# Clean up
if {[file exists $PREFS:HTMLtmp:incl]} {rm -r $PREFS:HTMLtmp:incl}
if {[file exists $PREFS:HTMLtmp:xincl]} {rm -r $PREFS:HTMLtmp:xincl}
unset htmlUpdateErr htmlUpdateList htmlUpdateBase htmlUpdatePath
}
proc htmlUpdateOneFile {f f1 folder inclFldr depth} {
global htmlUpdateErr htmlUpdateBase htmlUpdatePath htmlUpdateHome htmlURLAttr
if {[catch {open $f1} fid]} {return 0}
message "Updating [file tail $f1]…"
set sexpr {<!--[ \t\r\n]+#INCLUDE[ \t\r\n]+[^>]+>}
set eexpr {<!--[ \t\r\n]+/#INCLUDE[ \t\r\n]+[^>]+>}
set exp "([join $htmlURLAttr |])"
set exprr1 "<!--|\[ \\t\\n\\r\]+$exp\"?(\[^ \\t\\n\\r\">\]+)\"?"
set exprr2 {/\*|[ \t\n\r]+(url)\(\"?([^\"\)]+)\"?\)}
set commStart1 "<!--"
set commEnd1 "-->"
set commStart2 {/*}
set commEnd2 {\*/}
getFileInfo $f1 finfo
if {!$depth} {set created $finfo(created)}
set filecont [read $fid 16384]
set limit [expr [eof $fid] ? 0 : 300]
regsub -all "\n\r" $filecont "\r" filecont
if {[regexp {\n} $filecont]} {
set newln "\n"
} else {
set newln "\r"
}
set linenum 1
set ismod 0
set errf [string range $f [expr [string length $folder] + 1] end]
set temp [htmlOpenAfile]
set tmpfid [lindex $temp 0]
if {$depth} {puts $tmpfid "$htmlUpdateBase$htmlUpdatePath"}
set opening 0
set l [expr 20 - [string length [file tail $f]]]
while {1} {
while {$opening || ([regexp -nocase -indices $sexpr $filecont res] &&
[expr [string length $filecont] - [lindex $res 0]] > $limit)} {
if {!$opening} {
incr linenum [regsub -all $newln [string range $filecont 0 [lindex $res 0]] {} dummy]
set ln [expr 5 - [string length $linenum]]
puts -nonewline $tmpfid [string range $filecont 0 [lindex $res 1]]
set readName [string range $filecont [lindex $res 0] [lindex $res 1]]
set filecont [string range $filecont [expr [lindex $res 1] + 1] end]
}
if {![regexp -nocase -indices $eexpr $filecont res1] ||
[expr [string length $filecont] - [lindex $res1 0]] <= $limit} {
if {[eof $fid]} {
append htmlUpdateErr [htmlBrwsErr $errf $l $linenum $ln "Opening include tag without a matching end tag." $f]
} else {
set opening 1
}
break
}
set toReplace [string trim [string range $filecont 0 [expr [lindex $res1 0] - 1]]]
set opening 0
if {[regexp -nocase -indices $sexpr $filecont res2]
&& [lindex $res2 0] < [lindex $res1 0]} {
append htmlUpdateErr [htmlBrwsErr $errf $l $linenum $ln "Nested include tags." $f]
puts -nonewline $tmpfid [string range $filecont 0 [lindex $res1 1]]
incr linenum [regsub -all $newln [string range $filecont 0 [lindex $res1 1]] {} dummy]
set filecont [string range $filecont [expr [lindex $res1 1] + 1] end]
continue
}
if {[catch {htmlReadInclude $readName 0 $inclFldr $depth} text]} {
append htmlUpdateErr [htmlBrwsErr $errf $l $linenum $ln $text $f]
puts -nonewline $tmpfid [string range $filecont 0 [lindex $res1 1]]
incr linenum [regsub -all $newln [string range $filecont 0 [lindex $res1 1]] {} dummy]
set filecont [string range $filecont [expr [lindex $res1 1] + 1] end]
continue
}
if {[string trim $text] != $toReplace} {
set ismod 1
}
puts -nonewline $tmpfid "$newln$newln$text$newln$newln"
puts -nonewline $tmpfid [string range $filecont [lindex $res1 0] [lindex $res1 1]]
incr linenum [regsub -all $newln [string range $filecont 0 [lindex $res1 1]] {} dummy]
set filecont [string range $filecont [expr [lindex $res1 1] + 1] end]
}
if {![eof $fid]} {
if {$opening} {
append filecont [read $fid 16384]
} else {
puts -nonewline $tmpfid [string range $filecont 0 [expr [string length $filecont] - 301]]
incr linenum [regsub -all $newln [string range $filecont 0 [expr [string length $filecont] - 301]] {} dummy]
set filecont "[string range $filecont [expr [string length $filecont] - 300] end][read $fid 16384]"
}
set limit [expr [eof $fid] ? 0 : 300]
} else {
break
}
}
close $fid
if {$ismod || $depth} {puts -nonewline $tmpfid $filecont}
close $tmpfid
if {$ismod && !$depth} {
set linenum 1
set opening 0
set done 0
set fid [open [set temp1 [lindex $temp 1]]]
set filecont [read $fid 16384]
set limit [expr [eof $fid] ? 0 : 300]
set temp [htmlOpenAfile]
set tmpfid [lindex $temp 0]
while {1} {
if {$opening || ([regexp -nocase -indices {<!--[ \t\r\n]+#LASTMODIFIED[ \t\r\n]+[^>]+>} $filecont res] &&
[expr [string length $filecont] - [lindex $res 0]] > $limit)} {
if {!$opening} {
incr linenum [regsub -all "\n" [string range $filecont 0 [lindex $res 0]] {} dummy]
set ln [expr 5 - [string length $linenum]]
puts -nonewline $tmpfid [string range $filecont 0 [lindex $res 1]]
set lastMod [string range $filecont [lindex $res 0] [lindex $res 1]]
set filecont [string range $filecont [expr [lindex $res 1] + 1] end]
}
if {![regexp -nocase -indices {<!--[ \t\r\n]+/#LASTMODIFIED[ \t\r\n]+[^>]+>} $filecont res1] ||
[expr [string length $filecont] - [lindex $res1 0]] <= $limit} {
if {[eof $fid]} {
append htmlUpdateErr [htmlBrwsErr $errf $l $linenum $ln "Opening 'last modified' tag without a matching closing tag." $f]
} else {
set opening 1
}
} else {
set str [htmlGetLastMod $lastMod]
set done 1
if {$str == "0"} {
append htmlUpdateErr [htmlBrwsErr $errf $l $linenum $ln "Invalid 'last modified' tags." $f]
} else {
puts -nonewline $tmpfid "\r$str\r[string range $filecont [lindex $res1 0] end]"
set filecont ""
}
}
}
if {![eof $fid] && !$done} {
if {$opening} {
append filecont [read $fid 16384]
} else {
puts -nonewline $tmpfid [string range $filecont 0 [expr [string length $filecont] - 301]]
incr linenum [regsub -all "\n" [string range $filecont 0 [expr [string length $filecont] - 301]] {} dummy]
set filecont "[string range $filecont [expr [string length $filecont] - 300] end][read $fid 16384]"
}
set limit [expr [eof $fid] ? 0 : 300]
} else {
break
}
}
puts -nonewline $tmpfid $filecont
while {![eof $fid]} {
puts -nonewline $tmpfid [read $fid 16384]
}
close $fid
close $tmpfid
if {[catch {removeFile $f1}] && [file exists $f1]} {
append htmlUpdateErr "$errf[format "%$l\s" ""]; Could not write update to file. An error occurred.\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t∞$f\r"
} else {
catch {copyFile [lindex $temp 1] $f1; setFileInfo $f1 created $created}
}
catch {removeFile $temp1}
} elseif {$depth} {
set fid [open [set temp1 [lindex $temp 1]]]
set filecont [read $fid 16384]
set limit [expr [eof $fid] ? 0 : 300]
set temp [htmlOpenAfile]
set tempf [lindex $temp 1]
set tempfid [lindex $temp 0]
for {set i1 1} {$i1 < 3} {incr i1} {
if {$i1 == 2} {
close $fid
seek $tempfid 0
set fid $tempfid
set filecont [read $fid 16384]
set limit [expr [eof $fid] ? 0 : 300]
set temp [htmlOpenAfile]
set tempfid [lindex $temp 0]
}
set commStart [set commStart$i1]
set commEnd [set commEnd$i1]
set exprr [set exprr$i1]
set comment 0
while {1} {
while {$comment || ([regexp -nocase -indices $exprr $filecont href b url] &&
[expr [string length $filecont] - [lindex $href 0]] > $limit)} {
# Comment?
if {$comment || [string range $filecont [lindex $href 0] [lindex $href 1]] == $commStart} {
if {$comment} {
set href {0 0}
set subcont $filecont
} else {
set subcont [string range $filecont [expr [lindex $href 1] + 1] end]
}
if {[regexp -indices -- $commEnd $subcont cend] &&
[expr [string length $subcont] - [lindex $cend 0]] > $limit} {
puts -nonewline $tempfid [string range $filecont 0 [expr [lindex $href 1] + [lindex $cend 1] - 1]]
set filecont [string range $filecont [expr [lindex $href 1] + [lindex $cend 1]] end]
set comment 0
continue
} else {
set comment 1
break
}
}
set urltxt [string range $filecont [lindex $url 0] [lindex $url 1]]
set url2 [htmlURLunEscape $urltxt]
if {[regsub -nocase ":HOMEPAGE:" $url2 [lindex $htmlUpdateHome 1] url2]} {
if {[lindex $htmlUpdateHome 0] == $htmlUpdateBase} {
set newurl [htmlRelativePath $htmlUpdatePath $url2]
} else {
set newurl "[lindex $htmlUpdateHome 0]$url2"
}
set newurl [htmlURLescape2 $newurl]
} else {
set newurl $urltxt
}
puts -nonewline $tempfid [string range $filecont 0 [expr [lindex $url 0] - 1]]
puts -nonewline $tempfid $newurl
set filecont [string range $filecont [expr [lindex $url 1] + 1] end]
}
if {![eof $fid]} {
puts -nonewline $tempfid [string range $filecont 0 [expr [string length $filecont] - 301]]
set filecont "[string range $filecont [expr [string length $filecont] - 300] end][read $fid 16384]"
set limit [expr [eof $fid] ? 0 : 300]
} else {
break
}
}
puts -nonewline $tempfid $filecont
}
close $fid
close $tempfid
if {[catch {removeFile $f1}] && [file exists $f1]} {
append htmlUpdateErr "$errf[format "%$l\s" ""]; Could not write update to file. An error occurred.\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t∞$f\r"
} else {
catch {copyFile [lindex $temp 1] $f1}
}
catch {removeFile $temp1}
}
catch {removeFile [lindex $temp 1]}
catch {removeFile $tempf}
return $ismod
}
# Read content of a file to be included.
proc htmlReadInclude {incl nr fldr depth {onlyThis ""}} {
global PREFS htmlUpdateList htmlUpdateBase htmlUpdatePath
set htmlUpdateList [lrange $htmlUpdateList 0 $depth]
if {![regexp -nocase {file=\"([^\"]+)\"} $incl dum fil]} {
error "Invalid opening include tag."
}
if {$onlyThis != "" && $fil != $onlyThis} {error "Not this file"}
if {$depth == 10} {error "Too deep recursive includes."}
if {$fldr == "" && [regexp -nocase {^:INCLUDE:} $fil]} {error ":INCLUDE: doesn't map to a folder."}
set fil [htmlResolveInclPath [htmlUnQuote $fil] $fldr]
if {[lsearch -exact $htmlUpdateList $fil] >= 0} {error "Infinite loop of includes."}
if {![file exists $fil]} {
error "File not found."
}
lappend htmlUpdateList $fil
if {[string match "$fldr*" $fil]} {
set folder [string trimright $fldr :]
set tmpfil "HTMLtmp:incl:[string range $fil [string length $fldr] end]"
} else {
set folder [file dirname $fil]
set tmpfil "HTMLtmp:xincl:$fil"
}
if {![file exists "$PREFS:$tmpfil"] || ![htmlUpdateSameBase $tmpfil]} {
foreach d [split [file dirname $tmpfil] :] {
append d1 ":$d"
if {![file exists "$PREFS$d1"]} {mkdir "$PREFS$d1"}
}
if {[file exists "$PREFS:$tmpfil"]} {catch {removeFile "$PREFS:$tmpfil"}}
catch {copyFile $fil "$PREFS:$tmpfil"}
htmlUpdateOneFile $fil "$PREFS:$tmpfil" $folder [htmlWhichInclFolder $fil] [incr depth]
}
if {[catch {open "$PREFS:$tmpfil"} fid]} {
error "Could not read file."
}
gets $fid
set text [read $fid]
close $fid
regsub -all "\n\r" $text "\r" text
if {$nr} {regsub -all "\n" $text "\r" text}
# Remove include tags from inserted text
regsub -all -nocase "<!--\[ \t\r\n\]+/?#INCLUDE\[ \t\r\n\]+\[^>\]+>" $text "" text
return $text
}
proc htmlUpdateSameBase {fil} {
global htmlUpdateBase htmlUpdatePath PREFS
if {[catch {open $PREFS:$fil} fid]} {return 0}
set l [gets $fid]
close $fid
if {$l == "$htmlUpdateBase$htmlUpdatePath"} {return 1}
return 0
}